package cn.px.office.poi.excel.export;

import cn.px.office.annotation.ExcelTarget;
import cn.px.office.enums.ExcelDataTypeEnum;
import cn.px.office.poi.excel.entity.ExportParams;
import cn.px.office.poi.excel.entity.enmus.ExcelType;
import cn.px.office.poi.excel.entity.params.ExcelExportEntity;
import cn.px.office.poi.excel.entity.params.ExcelRowParams;
import cn.px.office.poi.excel.entity.vo.PoiBaseConstants;
import cn.px.office.poi.excel.export.base.AbstractExcelExportBase;
import cn.px.office.poi.excel.export.styler.IExcelExportStyler;
import cn.px.office.poi.exception.excel.ExcelExportException;
import cn.px.office.poi.exception.excel.enums.ExcelExportEnum;
import cn.px.office.poi.util.PoiPublicUtil;
import cn.px.office.vo.CustomCell;
import cn.px.office.vo.CustomMerge;
import cn.px.office.vo.CustomMergeVO;
import cn.px.office.vo.ExcelData;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.apache.poi.ss.usermodel.*;
import org.apache.poi.ss.util.CellRangeAddress;

import java.lang.reflect.Field;
import java.util.*;

/**
 * Excel导出服务
 * 导出是通过style是否有format决定渲染什么类型值的
 * style获取的规则
 * 先获取ExcelData中的style属性，
 * 再获取CustomCell中的ExcelExportEntity中获取style
 * 再通过ExcelExportEntity获取style样式渲染
 * <p>
 * 渲染数据：
 * 正常是通过ExcelExportEntity反射VO的数据
 * 自定义的：
 * int型的key则是通过直接写入指定列中数据
 * key型是通过map的get方法获取的指定位置值渲染
 * ExcelExportEntity对象的获取，先获取CustomCell的ExcelExportEntity对象，没有再获取当前key值的ExcelExportEntity
 * 左右也会合并
 *
 * @author 品讯科技
 * @create 2017-08-10
 */
@Slf4j
public class CustomExcelExportMergeServer extends AbstractExcelExportBase {

    /**
     * 最大行数,超过自动多Sheet
     */
    private static final int MAX_NUM = 60000;

    /**
     * 创建表头和标题
     *
     * @param entity
     * @param sheet
     * @param workbook
     * @param excelParams
     * @return
     */
    private int createHeaderAndTitle(ExportParams entity, Sheet sheet, Workbook workbook, List<ExcelExportEntity> excelParams) {
        int rows = 0, feildWidth = getFieldWidth(excelParams);
        if (entity.getTitle() != null) {
            rows += createHeaderRow(entity, sheet, workbook, feildWidth);
        }
        rows += createTitleRow(entity, sheet, workbook, rows, excelParams);
//		sheet.createFreezePane(0, rows, 0, rows);
        return rows;
    }

    /**
     * 创建 表头改变
     *
     * @param entity
     * @param sheet
     * @param workbook
     * @param feildWidth
     */
    public int createHeaderRow(ExportParams entity, Sheet sheet, Workbook workbook, int feildWidth) {
        Row row = sheet.createRow(0);
        row.setHeight(entity.getTitleHeight());
        createStringCell(row, 0, entity.getTitle(), getExcelExportStyler().getHeaderStyle(entity.getHeaderColor()), null);
        for (int i = 1; i <= feildWidth; i++) {
            createStringCell(row, i, "", getExcelExportStyler().getHeaderStyle(entity.getHeaderColor()), null);
        }
        sheet.addMergedRegion(new CellRangeAddress(0, 0, 0, feildWidth));
        if (entity.getSecondTitle() != null) {
            row = sheet.createRow(1);
            row.setHeight(entity.getSecondTitleHeight());
            CellStyle style = workbook.createCellStyle();
            style.setAlignment(CellStyle.ALIGN_RIGHT);
            createStringCell(row, 0, entity.getSecondTitle(), style, null);
            for (int i = 1; i <= feildWidth; i++) {
                createStringCell(row, i, "", getExcelExportStyler().getHeaderStyle(entity.getHeaderColor()), null);
            }
            sheet.addMergedRegion(new CellRangeAddress(1, 1, 0, feildWidth));
            return 2;
        }
        return 1;
    }

    /**
     * 创建表头
     *
     * @param title
     * @param index
     */
    private int createTitleRow(ExportParams title, Sheet sheet, Workbook workbook, int index, List<ExcelExportEntity> excelParams) {
        Row row = sheet.createRow(index);
        int rows = getRowNums(excelParams);
        row.setHeight((short) 450);
        Row listRow = null;
        if (rows == 2) {
            listRow = sheet.createRow(index + 1);
            listRow.setHeight((short) 450);
        }
        int cellIndex = 0;
        CellStyle titleStyle = getExcelExportStyler().getTitleStyle(title.getColor());
        for (int i = 0, exportFieldTitleSize = excelParams.size(); i < exportFieldTitleSize; i++) {
            ExcelExportEntity entity = excelParams.get(i);
            if (StringUtils.isNotBlank(entity.getName())) {
                createStringCell(row, cellIndex, entity.getName(), titleStyle, entity);
            }
            if (entity.getList() != null) {
                List<ExcelExportEntity> sTitel = entity.getList();
                if (StringUtils.isNotBlank(entity.getName())) {
                    sheet.addMergedRegion(new CellRangeAddress(index, index, cellIndex, cellIndex + sTitel.size() - 1));
                }
                for (int j = 0, size = sTitel.size(); j < size; j++) {
                    createStringCell(rows == 2 ? listRow : row, cellIndex, sTitel.get(j).getName(), titleStyle, entity);
                    cellIndex++;
                }
                cellIndex--;
            } else if (rows == 2) {
                createStringCell(listRow, cellIndex, "", titleStyle, entity);
                sheet.addMergedRegion(new CellRangeAddress(index, index + 1, cellIndex, cellIndex));
            }
            cellIndex++;
        }
        return rows;

    }

    /**
     * 判断表头是只有一行还是两行
     *
     * @param excelParams
     * @return
     */
    private int getRowNums(List<ExcelExportEntity> excelParams) {
        for (int i = 0; i < excelParams.size(); i++) {
            if (excelParams.get(i).getList() != null && StringUtils.isNotBlank(excelParams.get(i).getName())) {
                return 2;
            }
        }
        return 1;
    }

    private ExcelExportEntity indexExcelEntity(ExportParams entity) {
        ExcelExportEntity exportEntity = new ExcelExportEntity();
        exportEntity.setOrderNum(0);
        exportEntity.setName(entity.getIndexName());
        exportEntity.setWidth(10);
        exportEntity.setFormat(PoiBaseConstants.IS_ADD_INDEX);
        return exportEntity;
    }


    public void createCustomSheet(Workbook workbook, ExportParams entity, Class<?> pojoClass, Collection<?> dataSet) {
        if (log.isDebugEnabled()) {
            log.debug("Excel export start ,class is {}", pojoClass);
            log.debug("Excel version is {}", entity.getType().equals(ExcelType.HSSF) ? "03" : "07");
        }
        if (workbook == null || entity == null || pojoClass == null || dataSet == null) {
            throw new ExcelExportException(ExcelExportEnum.PARAMETER_ERROR);
        }
        super.type = entity.getType();
        long maxNum = MAX_NUM;
        if (type.equals(ExcelType.XSSF)) {
            maxNum = 1000000;
        }
        Sheet sheet = null;
        try {
            sheet = workbook.createSheet(entity.getSheetName());
        } catch (Exception e) {
            // 重复遍历,出现了重名现象,创建非指定的名称Sheet
            sheet = workbook.createSheet();
        }
        try {
            dataHanlder = entity.getDataHanlder();
            if (dataHanlder != null) {
                needHanlderList = Arrays.asList(dataHanlder.getNeedHandlerFields());
            }
            // 创建表格样式
            setExcelExportStyler((IExcelExportStyler) entity.getStyle().getConstructor(Workbook.class).newInstance(workbook));
            Drawing patriarch = sheet.createDrawingPatriarch();
            List<ExcelExportEntity> excelParams = new ArrayList<ExcelExportEntity>();
            if (entity.isAddIndex()) {
                excelParams.add(indexExcelEntity(entity));
            }
            // 得到所有字段
            Field[] fields = PoiPublicUtil.getClassFields(pojoClass);
            ExcelTarget etarget = pojoClass.getAnnotation(ExcelTarget.class);
            String targetId = etarget == null ? null : etarget.value();
            getAllExcelField(entity.getExclusions(), targetId, fields, excelParams, pojoClass, null);
            sortAllParams(excelParams);
            int index = entity.isCreateHeadRows() ? createHeaderAndTitle(entity, sheet, workbook, excelParams) : 0;
            short rowHeight = getRowHeight(excelParams);
            index += entity.getCustomTitleList() != null ? createCustomHeaderAndTitle(entity, sheet, workbook, excelParams, index) : 0;
            int titleHeight = index;
            setCellWith(excelParams, sheet);

            setCurrentIndex(1);
            Iterator<?> its = dataSet.iterator();
            List<Object> tempList = new ArrayList<Object>();
            List<CustomMergeVO> rowMergeList = new ArrayList<>();
            while (its.hasNext()) {
                ExcelData excelData = (ExcelData) its.next();
                // 判断是数据   还是自定义行
                // 是数据时，渲染数据
                if (excelData.getType().equals(ExcelDataTypeEnum.TYPE_VO.getValue())) {
                    Object t = excelData.getData();
                    index += createCustomCells(patriarch, index, t, excelData.getMergeMap(), excelParams, sheet, workbook, rowHeight, rowMergeList);
                    tempList.add(t);
                }
                if (excelData.getType().equals(ExcelDataTypeEnum.TYPE_CUSTOM_INTEGER.getValue())) {
                    // 是自定义行时，渲染自定义行数据
                    index += createCustomCellsForInteger(patriarch, index, excelData, excelParams, sheet, workbook, rowHeight, rowMergeList);
                    tempList.add(excelData);
                }
                if (excelData.getType().equals(ExcelDataTypeEnum.TYPE_CUSTOM_KEY.getValue())) {

                    index += createKeyCustomCells(patriarch, index, excelData, excelParams, sheet, workbook, rowHeight, rowMergeList);
                    tempList.add(excelData);
                }

                if (index >= maxNum) {
                    break;
                }
            }
//            mergeCells(sheet, excelParams, titleHeight);
            // 合并行
            for (CustomMergeVO customMergeVO : rowMergeList) {
                sheet.addMergedRegion(new CellRangeAddress(customMergeVO.getFirstRow(), customMergeVO.getLastRow(), customMergeVO.getFirstColumn(), customMergeVO.getLastColumn()));
            }
//			if (entity.getFreezeCol() != 0) {
//				sheet.createFreezePane(entity.getFreezeCol(), 0, entity.getFreezeCol(), 0);
//			}

            its = dataSet.iterator();
            for (int i = 0, le = tempList.size(); i < le; i++) {
                its.next();
                its.remove();
            }
            // 创建合计信息
            addStatisticsRow(getExcelExportStyler().getStyles(true, null), sheet);

            // 发现还有剩余list 继续循环创建Sheet
            if (dataSet.size() > 0) {
                createCustomSheet(workbook, entity, pojoClass, dataSet);
            }

        } catch (Exception e) {
            log.error(e.getMessage(), e);
            log.error(e.getMessage(), e);
            throw new ExcelExportException(ExcelExportEnum.EXPORT_ERROR, e.getCause());
        }
    }

    public void createCustomSheetForMap(Workbook workbook, ExportParams entity, List<ExcelExportEntity> entityList, Collection<? extends ExcelData> dataSet) {
        if (log.isDebugEnabled()) {
            log.debug("Excel version is {}", entity.getType().equals(ExcelType.HSSF) ? "03" : "07");
        }
        if (workbook == null || entity == null || entityList == null || dataSet == null) {
            throw new ExcelExportException(ExcelExportEnum.PARAMETER_ERROR);
        }
        super.type = entity.getType();
        long maxNum = MAX_NUM;
        if (type.equals(ExcelType.XSSF)) {
            maxNum = 1000000;
        }
        Sheet sheet = null;
        try {
            sheet = workbook.createSheet(entity.getSheetName());
        } catch (Exception e) {
            // 重复遍历,出现了重名现象,创建非指定的名称Sheet
            sheet = workbook.createSheet();
        }
        try {
            dataHanlder = entity.getDataHanlder();
            if (dataHanlder != null) {
                needHanlderList = Arrays.asList(dataHanlder.getNeedHandlerFields());
            }
            // 创建表格样式
            setExcelExportStyler((IExcelExportStyler) entity.getStyle().getConstructor(Workbook.class).newInstance(workbook));
            Drawing patriarch = sheet.createDrawingPatriarch();
            List<ExcelExportEntity> excelParams = new ArrayList<ExcelExportEntity>();
            if (entity.isAddIndex()) {
                excelParams.add(indexExcelEntity(entity));
            }
            excelParams.addAll(entityList);
            sortAllParams(excelParams);
            int index = entity.isCreateHeadRows() ? createHeaderAndTitle(entity, sheet, workbook, excelParams) : 0;
            short rowHeight = getRowHeight(excelParams);
            index += entity.getCustomTitleList() != null ? createCustomHeaderAndTitle(entity, sheet, workbook, excelParams, index) : 0;
            int titleHeight = index;
            setCellWith(excelParams, sheet);
            setCurrentIndex(1);
            Iterator<?> its = dataSet.iterator();
            List<Object> tempList = new ArrayList<Object>();
            List<CustomMergeVO> rowMergeList = new ArrayList<>();
            while (its.hasNext()) {

                ExcelData excelData = (ExcelData) its.next();
                // 判断是数据   还是自定义行
                // 是数据时，渲染数据
                if (excelData.getType().equals(ExcelDataTypeEnum.TYPE_VO.getValue())) {
                    Object t = excelData.getData();
                    index += createCustomCells(patriarch, index, t, excelData.getMergeMap(), excelParams, sheet, workbook, rowHeight, rowMergeList);
                    tempList.add(t);
                }
                if (excelData.getType().equals(ExcelDataTypeEnum.TYPE_CUSTOM_INTEGER.getValue())) {
                    // 是自定义行时，渲染自定义行数据
                    index += createCustomCellsForInteger(patriarch, index, excelData, excelParams, sheet, workbook, rowHeight, rowMergeList);
                    tempList.add(excelData);
                }
                if (excelData.getType().equals(ExcelDataTypeEnum.TYPE_CUSTOM_KEY.getValue())) {
                    index += createKeyCustomCells(patriarch, index, excelData, excelParams, sheet, workbook, rowHeight, rowMergeList);
                    tempList.add(excelData);
                }

                if (index >= maxNum) {
                    break;
                }
            }
//			if (entity.getFreezeCol() != 0) {
//				sheet.createFreezePane(entity.getFreezeCol(), 0, entity.getFreezeCol(), 0);
//			}

            // mergeCells(sheet, excelParams, titleHeight);
            // 合并行
            for (CustomMergeVO customMergeVO : rowMergeList) {
                sheet.addMergedRegion(new CellRangeAddress(customMergeVO.getFirstRow(), customMergeVO.getLastRow(), customMergeVO.getFirstColumn(), customMergeVO.getLastColumn()));
            }
            its = dataSet.iterator();
            for (int i = 0, le = tempList.size(); i < le; i++) {
                its.next();
                its.remove();
            }
            // 发现还有剩余list 继续循环创建Sheet
            if (dataSet.size() > 0) {
                createCustomSheetForMap(workbook, entity, entityList, dataSet);
            }

        } catch (Exception e) {
            log.error(e.getMessage(), e);
            throw new ExcelExportException(ExcelExportEnum.EXPORT_ERROR, e.getCause());
        }
    }

    /**
     * 创建VO与Map 最主要的 Cells
     *
     * @param rowHeight
     * @throws Exception
     */
    public int createCustomCells(Drawing patriarch, int index, Object t, Map<Object, CustomMerge> mergeMap,
                                 List<ExcelExportEntity> excelParams, Sheet sheet, Workbook workbook, short rowHeight
            , List<CustomMergeVO> rowMergeList) throws Exception {
        ExcelExportEntity entity;
        Row row = sheet.createRow(index);
        row.setHeight(rowHeight);
        int maxHeight = 1, cellNum = 0;
        int indexKey = createIndexCell(row, index, excelParams.get(0));
        cellNum += indexKey;
        for (int k = indexKey, paramSize = excelParams.size(); k < paramSize; k++) {
            entity = excelParams.get(k);
            if (entity.getList() != null) {
                // TODO: future 2020/2/28 暂时不管，复杂的难记住
                throw new Exception("表格参数错误");
            } else {
                Object value = getCellValue(entity, t);
                if (entity.getType() == 1) {
                    createStringCell(row, cellNum, value == null ? "" : value.toString(), getStyles(false, entity, null, workbook), entity);
                    // 合并自定义单元格,合并左右单元格
                    Object cellKey = getCellKey(entity, t);
                    CustomMerge merge = mergeMap.get(cellKey);
                    if (merge != null) {
                        // 解决左右合并问题
                        if (merge.getCellSpan() != null && merge.getCellSpan() > 1) {
                            Integer cellIndex = cellNum;
                            ExcelExportEntity excelExportEntity = null;
                            for (int i = cellIndex; i < cellIndex + merge.getCellSpan(); i++) {
                                if (excelExportEntity == null && i < excelParams.size()) {
                                    excelExportEntity = excelParams.get(i);
                                }
                                Cell cell = sheet.getRow(index).getCell(i);
                                if (cell == null) {
                                    sheet.getRow(index).createCell(i).setCellStyle(getStyles(false, entity, null, workbook));
                                }
                            }
                            sheet.addMergedRegion(new CellRangeAddress(index, index, cellIndex, cellIndex + merge.getCellSpan() - 1));
                        }
                        if (merge.getRowSpan() != null && merge.getRowSpan() > 1) {
                            CustomMergeVO rowMerge = new CustomMergeVO(index, index + merge.getRowSpan() - 1, cellNum, cellNum);
                            rowMergeList.add(rowMerge);
                        }
                    }
                } else {
                    createImageCell(patriarch, entity, row, cellNum, value == null ? "" : value.toString(), t);
                }
                cellNum++;
            }
        }
        // 合并需要合并的单元格
        cellNum = 0;
        for (int k = indexKey, paramSize = excelParams.size(); k < paramSize; k++) {
            entity = excelParams.get(k);
            if (entity.getList() != null) {
                cellNum += entity.getList().size();
            } else if (entity.isNeedMerge()) {
                for (int i = index + 1; i < index + maxHeight; i++) {
                    sheet.getRow(i).createCell(cellNum);
                    sheet.getRow(i).getCell(cellNum).setCellStyle(getStyles(false, entity, null, workbook));
                }
                sheet.addMergedRegion(new CellRangeAddress(index, index + maxHeight - 1, cellNum, cellNum));
                cellNum++;
            }
        }
        // 合并自定义单元格,合并左右单元格
        // TODO: future 2020/2/28 暂时不用处理，使用时看是否处理
        return maxHeight;

    }

    /**
     * 创建VO与Map 最主要的 Cells
     *
     * @param rowHeight
     * @throws Exception
     */
    public int createKeyCustomCells(Drawing patriarch, int index, ExcelData excelData, List<ExcelExportEntity> excelParams,
                                    Sheet sheet, Workbook workbook, short rowHeight, List<CustomMergeVO> rowMergeList) throws Exception {
        ExcelExportEntity entity = null;
        Row row = sheet.createRow(index);
        row.setHeight(rowHeight);
        // 渲染数据
        Map<Object, CustomCell> data = (Map<Object, CustomCell>) excelData.getData();
        Map<Object, Object> t = new HashMap<>(data.size());
        data.forEach((key, value) -> t.put(key, value.getData()));
        Map<Object, CustomMerge> mergeMap = excelData.getMergeMap();
        int maxHeight = 1, cellNum = 0;
        int indexKey = createIndexCell(row, index, excelParams.get(0));
        cellNum += indexKey;
        for (int k = indexKey, paramSize = excelParams.size(); k < paramSize; k++) {
            CustomCell customCell = data.get(excelParams.get(k).getKey());
            if (customCell == null) {
                if (entity == null) {
                    entity = excelParams.get(k);
                }
                createStringCell(row, cellNum, "", getStyles(false, entity, excelData, workbook), entity);
                cellNum++;
                continue;
            }
            entity = customCell.getExcelExportEntity();
            if (entity == null) {
                entity = excelParams.get(k);
            }
            if (entity.getList() != null) {
                // TODO: future 2020/2/28 暂时不管，复杂的难记住
                throw new Exception("表格参数错误");
            } else {
                Object value = getCellValue(entity, t);

                if (entity.getType() == 1) {
                    createStringCell(row, cellNum, value == null ? "" : value.toString(), getStyles(false, entity, excelData, workbook), entity);
                    // 合并自定义单元格,合并左右单元格
                    this.mergeCellForTypeKey(workbook, sheet, excelData, customCell, index, cellNum, excelParams, entity, rowMergeList);
                } else {
                    createImageCell(patriarch, entity, row, cellNum, value == null ? "" : value.toString(), t);
                }
                cellNum++;
            }
        }
        // 合并需要合并的单元格
        cellNum = 0;
        for (int k = indexKey, paramSize = excelParams.size(); k < paramSize; k++) {
            entity = excelParams.get(k);
            if (entity.getList() != null) {
                cellNum += entity.getList().size();
            } else if (entity.isNeedMerge()) {
                for (int i = index + 1; i < index + maxHeight; i++) {
                    sheet.getRow(i).createCell(cellNum);
                    sheet.getRow(i).getCell(cellNum).setCellStyle(getStyles(false, entity, excelData, workbook));
                }
                sheet.addMergedRegion(new CellRangeAddress(index, index + maxHeight - 1, cellNum, cellNum));
                cellNum++;
            }
        }
        // 合并自定义单元格,合并左右单元格
        // TODO: future 2020/2/28 暂时不用处理，使用时看是否处理
        return maxHeight;

    }

    /**
     * 创建自定义为integer的 最主要的 Cells
     *
     * @param rowHeight
     * @throws Exception
     */
    public int createCustomCellsForInteger(Drawing patriarch, int index, ExcelData excelData,
                                           List<ExcelExportEntity> excelParams, Sheet sheet, Workbook workbook,
                                           short rowHeight, List<CustomMergeVO> rowMergeList) throws Exception {
        ExcelExportEntity entity;
        Row row = sheet.createRow(index);
        row.setHeight(rowHeight);
        int maxHeight = 1;
        createIndexCell(row, index, excelParams.get(0));
        // 渲染数据
        Map<Integer, CustomCell> data = (Map<Integer, CustomCell>) excelData.getData();
        for (CustomCell customCell : data.values()) {
            Integer cellIndex = (Integer) customCell.getCellIndex();
            entity = customCell.getExcelExportEntity();
            if (entity == null && cellIndex < excelParams.size()) {
                entity = excelParams.get(cellIndex);
            }
            Object value = getCustomCellValue(entity, customCell.getData());
            createStringCell(row, cellIndex, value == null ? "" : value.toString(), index % 2 == 0 ? getStyles(false, entity, excelData, workbook) : getStyles(true, entity, excelData, workbook), entity);
        }
        // 合并需要合并的单元格
        this.mergeCellForTypeInteger(workbook, sheet, excelData, index, excelParams, rowMergeList);
        return maxHeight;

    }

    /**
     * 创建表头和标题
     *
     * @param entity
     * @param sheet
     * @param workbook
     * @param excelParams
     * @return
     */
    private int createCustomHeaderAndTitle(ExportParams entity, Sheet sheet, Workbook workbook, List<ExcelExportEntity> excelParams, int index) throws Exception {
        int rows = 0, feildWidth = getFieldWidth(excelParams);
        if (entity.getTitle() != null) {
            rows += createHeaderRow(entity, sheet, workbook, feildWidth);
        }
        List<ExcelData> customTitleList = entity.getCustomTitleList();
        for (ExcelData excelData : customTitleList) {
            rows += createCustomTitleRow(excelData, entity, sheet, workbook, index + rows, excelParams);
        }
        return rows;
    }

    /**
     * 创建表头
     *
     * @param title
     * @param index
     */
    private int createCustomTitleRow(ExcelData excelData, ExportParams title, Sheet sheet, Workbook workbook, int index, List<ExcelExportEntity> excelParams) throws Exception {
        Row row = sheet.getRow(index);
        if (row == null) {
            row = sheet.createRow(index);
        }
        setRowParams(row, excelData.getExcelRowParams());
        int rowIndex = 0;
        int cellIndex = 0;

        if (excelData.getType().equals(ExcelDataTypeEnum.TYPE_CUSTOM_KEY.getValue())) {
            for (int i = 0, exportFieldTitleSize = excelParams.size(); i < exportFieldTitleSize; i++) {
                ExcelExportEntity entity = excelParams.get(i);
                Map<String, CustomCell> rowData = (Map<String, CustomCell>) excelData.getData();
                String key = (String) entity.getKey();
                CustomCell cellData = rowData.get(key);
                entity = cellData.getExcelExportEntity();
                if (entity == null && i < excelParams.size()) {
                    entity = excelParams.get(i);
                }
                CellStyle titleStyle = getCustomTitleStyle(entity, excelData, workbook, title);
                Object value = getCustomCellValue(entity, cellData.getData());
                createStringCell(row, cellIndex, value.toString(), titleStyle, entity);
                this.mergeCellForTypeKey(workbook, sheet, excelData, cellData, index, cellIndex, excelParams, entity, null);
                // 合并行单元格

                cellIndex++;
            }
            rowIndex = 1;
        }
        if (excelData.getType().equals(ExcelDataTypeEnum.TYPE_CUSTOM_INTEGER.getValue())) {
            Map<Integer, CustomCell> rowData = (Map<Integer, CustomCell>) excelData.getData();
            for (Integer myCellIndex : rowData.keySet()) {
                ExcelExportEntity entity = null;
                CustomCell cellData = rowData.get(myCellIndex);
                entity = cellData.getExcelExportEntity();
                if (entity == null && myCellIndex < excelParams.size()) {
                    entity = excelParams.get(myCellIndex);
                }
                CellStyle titleStyle = getCustomTitleStyle(entity, excelData, workbook, title);
                Object value = getCustomCellValue(entity, cellData.getData());
                createStringCell(row, myCellIndex, value.toString(), titleStyle, entity);
            }
            this.mergeCellRowForTypeInteger(workbook, sheet, excelData, index, excelParams);
            rowIndex = 1;
        }
        return rowIndex;
    }

    private CellStyle getCustomTitleStyle(ExcelExportEntity entity, ExcelData excelData, Workbook workbook, ExportParams title) {
        CellStyle titleStyle = null;
        if (entity != null && entity.getCellStyle() != null) {
            titleStyle = entity.getCellStyle().apply(workbook);
        }
        if (titleStyle == null && excelData.getCellStyle() != null) {
            titleStyle = excelData.getCellStyle().apply(workbook);
        }
        if (titleStyle == null) {
            titleStyle = getTitleStyles(title, excelData, workbook);
        }
        return titleStyle;
    }

    private void setRowParams(Row row, ExcelRowParams params) {
        Short height = (short) 450;
        if (params != null && params.getHeight() != null) {
            height = params.getHeight();
        }
        row.setHeight(height);
    }

    /**
     * 合并自定义Integer类型行
     *
     * @param workbook    ：
     * @param sheet       ：
     * @param excelData   :
     * @param rowIndex    :
     * @param excelParams ：
     */
    private void mergeCellForTypeInteger(Workbook workbook, Sheet sheet, ExcelData excelData, int rowIndex, List<ExcelExportEntity> excelParams, List<CustomMergeVO> rowMergeList) {
        Map<Object, CustomMerge> mergeMap = excelData.getMergeMap();
        if (mergeMap != null && mergeMap.size() > 0) {
            mergeMap.forEach((key, value) -> {
                Integer cellIndex = (Integer) value.getCellIndex();
                if (value.getCellSpan() != null && value.getCellSpan() > 1) {
                    ExcelExportEntity excelExportEntity = null;
                    for (int i = cellIndex; i < cellIndex + value.getCellSpan(); i++) {
                        if (excelExportEntity == null && i < excelParams.size()) {
                            excelExportEntity = excelParams.get(i);
                        }
                        Cell cell = sheet.getRow(rowIndex).getCell(i);
                        if (cell == null) {
                            sheet.getRow(rowIndex).createCell(i).setCellStyle(getStyles(false, excelExportEntity, excelData, workbook));
                        }
                    }
                    sheet.addMergedRegion(new CellRangeAddress(rowIndex, rowIndex, cellIndex, cellIndex + value.getCellSpan()));
                }
                if (value.getRowSpan() != null && value.getRowSpan() > 1) {
                    CustomMergeVO rowMerge = new CustomMergeVO(rowIndex, rowIndex + value.getRowSpan() - 1, cellIndex, cellIndex);
                    rowMergeList.add(rowMerge);
                }
            });

        }
    }

    /**
     * 合并自定义Key类型行
     *
     * @param workbook    ：
     * @param sheet       ：
     * @param excelData   :
     * @param rowIndex    :
     * @param excelParams ：
     */
    private void mergeCellForTypeKey(Workbook workbook, Sheet sheet, ExcelData excelData, CustomCell customCell,
                                     int rowIndex, int cellNum, List<ExcelExportEntity> excelParams, ExcelExportEntity excelParam
            , List<CustomMergeVO> rowMergeList) {
        Object cellKey = getCellKey(excelParam, customCell);
        Map<Object, CustomMerge> mergeMap = excelData.getMergeMap();
        CustomMerge merge = mergeMap.get(cellKey);
        if (merge != null) {
            // 解决左右合并问题
            if (merge.getCellSpan() != null && merge.getCellSpan() > 1) {
                Integer cellIndex = cellNum;
                ExcelExportEntity excelExportEntity = null;
                for (int i = cellIndex; i < cellIndex + merge.getCellSpan(); i++) {
                    if (excelExportEntity == null && i < excelParams.size()) {
                        excelExportEntity = excelParams.get(i);
                    }
                    Cell cell = sheet.getRow(rowIndex).getCell(i);
                    if (cell == null) {
                        sheet.getRow(rowIndex).createCell(i).setCellStyle(getStyles(false, excelExportEntity, excelData, workbook));
                    }
                }
                sheet.addMergedRegion(new CellRangeAddress(rowIndex, rowIndex, cellIndex, cellIndex + merge.getCellSpan() - 1));
            }
            if (rowMergeList != null && merge.getRowSpan() != null && merge.getRowSpan() > 1) {
                CustomMergeVO rowMerge = new CustomMergeVO(rowIndex, rowIndex + merge.getRowSpan() - 1, cellNum, cellNum);
                rowMergeList.add(rowMerge);
            }
        }
    }

    /**
     * 合并自定义Integer类型行
     *
     * @param workbook    ：
     * @param sheet       ：
     * @param excelData   :
     * @param rowIndex    :
     * @param excelParams ：
     */
    private void mergeCellRowForTypeInteger(Workbook workbook, Sheet sheet, ExcelData excelData, int rowIndex, List<ExcelExportEntity> excelParams) {
        Map<Object, CustomMerge> mergeMap = excelData.getMergeMap();
        if (mergeMap != null && mergeMap.size() > 0) {
            mergeMap.forEach((key, value) -> {
                int endCell = 0;
                int endRow = 0;
                int startCell = 0;
                if (value.getCellSpan() != null && value.getCellSpan() > 1) {
                    Integer cellIndex = (Integer) value.getCellIndex();
                    ExcelExportEntity excelExportEntity = null;
                    for (int i = cellIndex; i < cellIndex + value.getCellSpan(); i++) {
                        if (excelExportEntity == null && i < excelParams.size()) {
                            excelExportEntity = excelParams.get(i);
                        }
                        Cell cell = sheet.getRow(rowIndex).getCell(i);
                        if (cell == null) {
                            sheet.getRow(rowIndex).createCell(i).setCellStyle(getStyles(false, excelExportEntity, excelData, workbook));
                        }
                    }
                    endCell = cellIndex + value.getCellSpan() - 1;
                    endRow = rowIndex;
                    startCell = cellIndex;
                }
                if (value.getRowSpan() != null && value.getRowSpan() > 1) {
                    Integer cellIndex = (Integer) value.getCellIndex();
                    ExcelExportEntity excelExportEntity = null;
                    if (cellIndex < excelParams.size()) {
                        excelExportEntity = excelParams.get(cellIndex);
                    }
                    for (int i = rowIndex; i < rowIndex + value.getRowSpan(); i++) {
                        if (sheet.getRow(i) == null) {
                            sheet.createRow(i).createCell(cellIndex).setCellStyle(getStyles(false, excelExportEntity, excelData, workbook));
                        }
                        Cell cell = sheet.getRow(i).getCell(cellIndex);
                        if (cell == null) {
                            sheet.getRow(i).createCell(cellIndex).setCellStyle(getStyles(false, excelExportEntity, excelData, workbook));
                        }
                    }
                    if (endCell == 0) {
                        endCell = cellIndex;
                    }
                    endRow = rowIndex + value.getRowSpan() - 1;
                    startCell = cellIndex;
                }
                if (endRow != 0) {
                    sheet.addMergedRegion(new CellRangeAddress(rowIndex, endRow, startCell, endCell));
                }
            });

        }
    }

    @Override
    public CellStyle getStyles(boolean needOne, ExcelExportEntity entity) {
        return super.getStyles(needOne, entity);
    }

    public CellStyle getStyles(boolean needOne, ExcelExportEntity entity, ExcelData excelData, Workbook workbook) {
        if (excelData != null && excelData.getCellStyle() != null) {
            return excelData.getCellStyle().apply(workbook);
        }
        return super.getStyles(needOne, entity);
    }

    public CellStyle getTitleStyles(ExportParams title, ExcelData excelData, Workbook workbook) {
        if (excelData != null && excelData.getCellStyle() != null) {
            return excelData.getCellStyle().apply(workbook);
        }

        return getExcelExportStyler().getTitleStyle(title.getColor());
    }
}
